<template>
  <!-- @1 拖拽模式和大块区域上传 -->
  <a-upload-dragger
    v-if="mode === 'drag'"
    v-bind="$attrs"
    v-model:fileList="fileList"
    :list-type="listType"
    :name="name"
    :multiple="multiple"
    :before-upload="beforeUpload"
    :disabled="disabled"
    :show-upload-list="showUploadList"
    :custom-request="customRequest"
    @change="handleChange"
    @remove="onRemove"
    @preview="handlePreview"
  >
    <template v-if="customAction">
      <!-- 自定义区域 -->
      <slot name="operationArea" />
    </template>
    <template v-else>
      <!-- 判断是否是照片墙模式 -->
      <template v-if="listType === 'picture-card'">
        <div>
          <plus-outlined />
          <div class="ant-upload-text">Upload</div>
        </div>
      </template>
      <template v-else>
        <p class="ant-upload-drag-icon">
          <cloud-upload-outlined />
        </p>
        <p class="ant-upload-text">将文件拖到此处，或点击上传</p>
      </template>
    </template>
  </a-upload-dragger>

  <!-- @2 小按钮上传模式 -->
  <a-upload
    v-if="mode === 'small-button'"
    v-bind="$attrs"
    v-model:fileList="fileList"
    :name="name"
    :multiple="multiple"
    :list-type="listType"
    :before-upload="beforeUpload"
    :disabled="disabled"
    :show-upload-list="showUploadList"
    :custom-request="customRequest"
    @change="handleChange"
    @remove="onRemove"
    @preview="handlePreview"
  >
    <template v-if="customAction">
      <!-- 自定义上传区域 -->
      <slot name="operationArea" />
    </template>
    <template v-else>
      <!-- 判断是否是照片墙模式 -->
      <template v-if="listType === 'picture-card'">
        <div>
          <plus-outlined />
          <div class="ant-upload-text">Upload</div>
        </div>
      </template>
      <template v-else>
        <a-button>
          <upload-outlined></upload-outlined>
          上传文件
        </a-button>
      </template>
    </template>
  </a-upload>

  <!-- 图片预览区域 -->
  <a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
    <img alt="example" style="width: 100%" :src="previewImage" />
  </a-modal>
</template>
<script setup lang="ts">
import { message } from "ant-design-vue"
import type { UploadChangeParam } from "ant-design-vue"
import { removeFile, uploadFile } from "@/api/modules/file"
import { onMounted } from "vue"
const attrs: any = useAttrs()

interface IFile {
  name: string
  size: number
  type: string
  [propName: string]: any
}

interface Props {
  name?: string
  parasmData?: object
  multiple?: boolean
  accept?: string
  method?: string
  size?: number
  disabled?: boolean
  withCredentials?: boolean
  showUploadList?: boolean
  modelValue?: object[]
  mode?: string
  customAction?: boolean //是否自定义触发区域
  listType?: string
}

const props = withDefaults(defineProps<Props>(), {
  name: "file",
  method: "post",
  multiple: false,
  accept: "",
  size: 50,
  disabled: false,
  withCredentials: false,
  showUploadList: true,
  parasmData: () => ({}),
  modelValue: () => [],
  mode: "small-button",
  customAction: false,
  listType: "picture",
})

const emits = defineEmits<{
  (e: "update:modelValue", fileList: IFile[]): void
}>()

const fileList = ref<any>([])
const previewVisible = ref<boolean>(false)
const previewImage = ref<string | undefined>("")

//上传文件改变时的状态
const handleChange = (info: UploadChangeParam): void => {
  const status = info.file.status
  if (status === "done") {
    message.success("上传成功")
    let files: any = []
    Object.values(info.fileList).forEach(v => {
      if (v.response) v.response.name = v.response.fileName
      files.push(toRaw(v.response || v))
    })
    emits("update:modelValue", files)
  } else if (status === "error") {
    message.error(`${info?.file?.response?.message || "系统异常，请稍后重试"}`)
  }
}

// 附件是否超过最大尺寸
const exceedFileSize = (file: IFile): boolean => {
  return file.size > props.size * 1024 * 1024
}

//上传资源前进行拦截
const beforeUpload = (file: IFile): boolean => {
  let res = false

  //个数限制
  if (fileList.value?.length >= attrs["max-count"]) {
    message.error(`最多允许上传${fileList.value?.length}个附件`)
    return false
  }

  //资源大小判断
  if (exceedFileSize(file)) {
    let computerSize = file.size * 1024 * 1024
    message.error(`附件的大小为${computerSize}MB,超过了允许的最大尺寸${props.size}MB.`)
    res = false
  } else {
    res = true
  }

  //类型判断
  if (!props.accept) return true

  // 文件类型限制
  const name = file?.name || ""
  const ext: string = name.slice(name.lastIndexOf(".") + 1, name.length)
  const isExt = !props.accept.includes(ext)
  if (isExt) {
    res = false
    if (!props.accept) message.error("请配置可上传文件的格式!")
    else message.error(`上传的附件只能是${props.accept} "格式!`)
  }
  return res
}

//删除文件
const onRemove = async (file: IFile) => {
  const fileId: string = file?.response?.fileId || file?.fileId
  if (fileId) {
    try {
      await removeFile(fileId)
      message.success("删除成功")

      //从列表中删除项目，更新到父组件里面,删除成功后的文件没fileId了
      let newFileList: IFile[] = []
      Object.values(fileList.value).forEach((v: any) => {
        const vFileId = v?.response?.fileId || v.fileId
        if (vFileId != fileId) newFileList.push(toRaw(v.response || v))
      })
      emits("update:modelValue", newFileList)
      return true
    } catch (err: any) {
      if (err.message) {
        message.error(err.message)
        console.log("删除文件失败 >>>>>>>> ", err.value)
      }
      return false
    }
  }
}

//自定义上传
const customRequest = async (options: any): Promise<void> => {
  let { file, onProgress, onSuccess } = options
  file.status = "uploading"
  onProgress({ percent: 50 })
  let fm = new FormData()
  fm.append(props.name, file)
  fm.append("securityLevel", "0")

  //添加自定义上传参数
  const parasmData = props.parasmData
  if (parasmData && Object.keys(parasmData).length) for (const [key, value] of Object.entries(parasmData)) fm.append(`${key}`, value)
  try {
    const res = await uploadFile(fm)
    onProgress({ percent: 100 })
    onSuccess(res, file)
    file.status = "success"
  } catch (err: any) {
    if (err.message) {
      message.error(err.message)
      console.log("上传文件失败 >>>>>>>> ", err.value)
    }
  }
}

//预览
const handlePreview = (file: IFile): void => {
  const fileId = file.response?.fileId || file.fileId
  if (fileId) {
    previewImage.value = `/portal/file/onlinePreviewController/v1/getFileById_${fileId}`
    previewVisible.value = true
  }
}

//关闭预览
const handleCancel = (): void => {
  previewVisible.value = false
}

//回显上传过的文件
onMounted(() => {
  fileList.value = props.modelValue
})
</script>

<!-- 

  1. 限制上传1个文件时候，覆盖问题 {组件内部问题}
 -->
